package uk.co.q3c.deplan.server.unit.domain.task;

import java.util.Date;

import org.apache.log4j.Logger;
import org.testng.Assert;
import org.testng.annotations.Test;

import uk.co.q3c.deplan.client.domain.dag.ChangeInvalidException;
import uk.co.q3c.deplan.client.domain.dag.CycleDetectedException;
import uk.co.q3c.deplan.client.domain.resource.IndividualResource;
import uk.co.q3c.deplan.client.domain.resource.PersistenceReferenceException;
import uk.co.q3c.deplan.client.domain.resource.ResourceGroup;
import uk.co.q3c.deplan.client.domain.resource.ResourcePool;
import uk.co.q3c.deplan.client.domain.task.BaseTask;
import uk.co.q3c.deplan.server.util.Q3Calendar;

/**
 * @see BaseTask
 * @author DSowerby 29 Jun 2008 00:29:40
 * 
 */
@Test
public class ResourcedTask_UT extends DomainBase_UT {
	transient protected final Logger logger = Logger.getLogger(getClass().getName());
	BaseTask rt;
	ResourcePool pool;

	@Override
	protected void beforeMethod() throws Exception {
		super.beforeMethod();
		rt = createStandardTask(1);
		pool = new ResourcePool(connection);
		connection.openSession();
	}

	@Override
	protected void afterMethod() throws Exception {
		rt = null;
		pool = null;
		connection.closeSession();
		super.afterMethod();
	}

	@Test(enabled = true)
	public void relatedWork() throws PersistenceReferenceException {
		IndividualResource ir1 = addResource("A");
		rt.setName("Squishy bits");
		rt.setAssignedResource(ir1);
		rt.assignResource(ir1, 1);
		rt.setWorkRemaining(200);
		Assert.assertEquals(rt.getTotalWork(), 200);
		rt.setWorkDone(50, ir1, new Date());
		Assert.assertEquals(rt.getTotalWork(), 250);
	}

	/**
	 * as per description {@link BaseTask#setWorkRemaining()}
	 */
	@Test(enabled = true)
	public void workRemaining() {
		// actual plannedFinish should be cleared if there is more work to do
		rt.setActualFinish(new Date());
		rt.setWorkRemaining(400);
		Assert.assertEquals(rt.getTotalWork(), 400);
		Assert.assertNull(rt.getActualFinish());

		// attempt to set less than 0, changed to 0
		// remaining work to zero should have an actual plannedFinish
		Assert.assertNull(rt.getActualFinish());
		rt.setWorkRemaining(-5); // reset to 0
		Assert.assertEquals(rt.getWorkRemaining(), 0);
		Assert.assertNotNull(rt.getActualFinish());
	}

	@Test(enabled = true)
	public void workDone() throws PersistenceReferenceException {
		IndividualResource ir1 = addResource("A");
		rt.setName("scruff buttock");
		rt.setAssignedResource(ir1);
		rt.assignResource(ir1, 1);
		rt.setWorkDone(300, ir1, new Date());
		rt.setWorkRemaining(100);
		Assert.assertEquals(rt.getTotalWork(), 400);

	}

	@Test(enabled = true)
	public void actualStartFinish() throws PersistenceReferenceException {
		IndividualResource ir1 = addResource("A");
		rt.setAssignedResource(ir1);
		rt.assignResource(ir1, 1);
		rt.setActualFinish(new Date());
		rt.setWorkRemaining(0);
		rt.setWorkDone(10, ir1, new Date());
		rt.setActualStart(new Date(rt.getActualFinish()
				.getTime() + 1));

	}

	/**
	 * This is no longer a valid test. Profiles are created when a call is made to set planned work, work done or work remaining for an
	 * individual resource. Just assignning a resource does not cause a prolie to be created.
	 * 
	 * @throws PersistenceReferenceException
	 */
	@Test(enabled = false)
	public void createProfiles_groups() throws PersistenceReferenceException {

		IndividualResource ds = addResource("dsowerby");
		IndividualResource mp = addResource("mpaine");
		IndividualResource rd = addResource("rduck");
		ResourceGroup g1 = addResourceGroup("g1", "dsowerby", "mpaine");
		ResourceGroup g2 = addResourceGroup("g2", "mpaine", "rduck");

		BaseTask pt1 = addTask("pt1");
		pt1.assignResource(ds, 1);
		BaseTask pt2 = addTask("pt2");
		pt2.assignResource(mp, 1);
		BaseTask pt3 = addTask("pt3");
		pt3.assignResource(rd, 1);
		BaseTask pt4 = addTask("pt4");
		pt4.assignResource(g1, 1);
		BaseTask pt5 = addTask("pt5");
		pt5.assignResource(g2, 1);

		Assert.assertNotNull(pt4.getProfile(ds));
		Assert.assertNotNull(pt4.getProfile(mp));
	}

	@Test(enabled = true)
	public void dereference() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		BaseTask task = createStandardTask(2);
		// Project project = createProject(5);
		BaseTask project = createProject("project");
		BaseTask successor = createStandardTask(3);
		BaseTask predecessor = createStandardTask(4);
		task.setParentTask(project);

		Assert.assertEquals(task.getParentTask()
				.toString(), project.toString());

		task.addPredecessor(predecessor);
		Assert.assertTrue(task.hasPredecessor(predecessor));

		task.addSuccessor(successor);
		Assert.assertTrue(task.hasSuccessor(successor));

		task.dereference();
		Assert.assertEquals(task.getParentTask(), null);
		Assert.assertFalse(task.hasSuccessor(successor));
		Assert.assertFalse(task.hasPredecessor(predecessor));

	}

	public void profiles() throws PersistenceReferenceException {
		IndividualResource ds = addResource("dsowerby");
		IndividualResource mp = addResource("mpaine");
		IndividualResource rd = addResource("rduck");
		ResourceGroup g1 = addResourceGroup("g1", "dsowerby", "mpaine");
		ResourceGroup g2 = addResourceGroup("g2", "mpaine", "rduck");
		g1.save();
		g2.save();
		BaseTask pt1 = addTask("pt1");
		pt1.assignResource(ds, 1);
		/*
		 * Set a planned value to a currently assigned resource
		 */
		Q3Calendar cal = new Q3Calendar(2009, 9, 12);
		ds.bookEffort(100, cal.getTime(), pt1);
		Assert.assertEquals(pt1.profileCount(), 1);
		Assert.assertEquals(pt1.getWorkPlanned(ds, cal.getTime()), 100);

		/*
		 * Set a work remaining value
		 */

		/*
		 * Set an actual value
		 */

		/*
		 * 
		 */

	}

	private IndividualResource addResource(String name) throws PersistenceReferenceException {
		IndividualResource r1 = new IndividualResource(connection);
		r1.setName(name);
		r1.save();
		pool.addResource(r1);
		return r1;
	}

	private BaseTask addTask(String name) {
		BaseTask pt = new BaseTask(connection);
		pt.setName(name);
		return pt;
	}

	private ResourceGroup addResourceGroup(String groupName, String r1name, String r2name) throws PersistenceReferenceException {
		ResourceGroup rg = new ResourceGroup(connection);
		rg.addResource((IndividualResource) pool.getResource(r1name));
		rg.addResource((IndividualResource) pool.getResource(r2name));
		rg.setName(groupName);
		rg.save();
		pool.addResource(rg);
		return rg;
	}

}
